package com.shop.cereshop.commons.config;

import com.fasterxml.jackson.core.JsonGenerator;
import com.fasterxml.jackson.databind.BeanProperty;
import com.fasterxml.jackson.databind.JsonSerializer;
import com.fasterxml.jackson.databind.SerializerProvider;
import com.fasterxml.jackson.databind.ser.ContextualSerializer;
import com.fasterxml.jackson.databind.ser.std.StdSerializer;
import com.shop.cereshop.commons.annotation.KeepLongAsNumber;

import java.io.IOException;

public class ConditionalLongSerializer extends StdSerializer<Long> implements ContextualSerializer {

    public ConditionalLongSerializer() {
        super(Long.class);
    }

    @Override
    public void serialize(Long value, JsonGenerator gen, SerializerProvider provider)
            throws IOException {
        // 当直接使用 @JsonSerialize 时，这里会被调用
        // 由于字段有 @KeepLongAsNumber 注解，我们直接保持为数值
        gen.writeNumber(value);
    }

    @Override
    public JsonSerializer<?> createContextual(SerializerProvider prov, BeanProperty property) {
        if (property != null) {
            try {
//                System.out.println("检查字段: " + property.getName() + ", 类型: " + property.getType());

                // 尝试获取字段的注解，而不是 getter 方法的注解
                if (property.getMember() != null) {
                    // 获取字段对象
                    java.lang.reflect.Field field = getFieldFromProperty(property);
                    if (field != null) {
//                        System.out.println("找到字段: " + field.getName());

                        // 检查字段上的注解
                        if (field.isAnnotationPresent(KeepLongAsNumber.class)) {
//                            System.out.println("字段 " + property.getName() + " 有 @KeepLongAsNumber 注解，使用数值序列化器");
                            return new KeepLongAsNumberSerializer();
                        } else {
//                            System.out.println("字段 " + property.getName() + " 没有 @KeepLongAsNumber 注解，使用字符串序列化器");
                        }
                    } else {
//                        System.out.println("无法获取字段对象");
                    }
                }
            } catch (Exception e) {
//                System.err.println("检查注解时发生错误: " + e.getMessage());
                e.printStackTrace();
            }
        } else {
            System.out.println("property 为 null");
        }
        // 如果没有注解，返回转换为字符串的序列化器
        return new ToStringSerializer();
    }

    /**
     * 从 BeanProperty 中获取对应的字段对象
     */
    private java.lang.reflect.Field getFieldFromProperty(BeanProperty property) {
        try {
            if (property.getMember() != null) {
                Class<?> declaringClass = property.getMember().getDeclaringClass();
                String fieldName = property.getName();

                // 尝试获取字段
                try {
                    return declaringClass.getDeclaredField(fieldName);
                } catch (NoSuchFieldException e) {
                    // 如果直接获取失败，尝试在父类中查找
                    Class<?> superClass = declaringClass.getSuperclass();
                    while (superClass != null && superClass != Object.class) {
                        try {
                            return superClass.getDeclaredField(fieldName);
                        } catch (NoSuchFieldException ex) {
                            superClass = superClass.getSuperclass();
                        }
                    }
                }
            }
        } catch (Exception e) {
            System.err.println("获取字段时发生错误: " + e.getMessage());
        }
        return null;
    }

    // 保持数值格式的序列化器
    private static class KeepLongAsNumberSerializer extends JsonSerializer<Long> {
        @Override
        public void serialize(Long value, JsonGenerator gen, SerializerProvider provider) throws IOException {
            gen.writeNumber(value);
        }
    }

    // 转换为字符串的序列化器
    private static class ToStringSerializer extends JsonSerializer<Long> {
        @Override
        public void serialize(Long value, JsonGenerator gen, SerializerProvider provider) throws IOException {
            gen.writeString(value.toString());
        }
    }
}